package com.wwy.monitor.util;

import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * æ¥æutil.
 *
 * @author chaozhe.mcz
 * @since jdk8
 */
public class DateUtil {
    private static Logger LOGGER = LoggerFactory.getLogger(DateUtil.class);
    public static String DEFAULT_PATTERN = "yyyyMMddHHmm";
    public static String PATTERN_PADDING_ZERO = "yyyyMMdd0000";
    public static String PATTERN_PADDING_59 = "yyyyMMdd2359";
    public static String PATTERN_PADDING_M_ZERO = "yyyyMMddHH00";
    public static String SHOW_PATTERN = "yyyy-MM-dd HH:mm";
    public static String SHOW_PATTERN_HMS = "yyyy-MM-dd HH:mm:ss";
    public static String SHOW_PATTERN_DATE = "yyyy-MM-dd";
    public static String SHOW_PATTERN_HMS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
    public static String SHOW_PATTERN_HMS_ZERO = "yyyy-MM-dd HH:mm:00";
    public static String SHOW_PATTERN_DATE_ZERO = "yyyy-MM-dd 00:00:00";

    public static String getNowDateTimeString() {
        return getNowDateTimeString(null);
    }

    public static String getNowDateTimeString(String pattern) {
        String p = DEFAULT_PATTERN;
        if (StringUtils.isNotBlank(pattern)) {
            p = pattern;
        }
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(p));
    }

    public static String getDateValue(Calendar calendar, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String date = sdf.format(calendar.getTime());
        return date;
    }

    public static String getDateValue(Calendar calendar) {
        return getDateValue(calendar, SHOW_PATTERN_DATE);
    }

    public static Date getNowDate() {
        return getNowDate(null);
    }

    public static Date getNowDate(String pattern) {
        String p = DEFAULT_PATTERN;
        if (StringUtils.isNotBlank(pattern)) {
            p = pattern;
        }
        try {
            return SimpleDateFormat.getInstance().parse(LocalDateTime.now().format(DateTimeFormatter.ofPattern(p)));
        } catch (ParseException e) {
            LOGGER.info("method [getNowDate] has error, ", e);
        }
        return null;
    }

    public static Date getLastMinute() {
        return getLastMinute(null);
    }

    public static Date getLastMinute(String pattern) {
        String p = DEFAULT_PATTERN;
        if (StringUtils.isNotBlank(pattern)) {
            p = pattern;
        }
        try {
            String s = LocalDateTime.now().minusMinutes(1).format(DateTimeFormatter.ofPattern(p));
            return SimpleDateFormat.getInstance().parse(s);
        } catch (ParseException e) {
            LOGGER.info("method [getLastMinute] has error, ", e);
        }
        return null;
    }

    public static String getLastMinuteString() {
        return getLastMinuteString(null);
    }

    public static String getLastMinuteString(String pattern) {
        return getMinuteWithInterval(pattern, -1);
    }

    public static String getMinuteWithInterval(int interval) {
        return getMinuteWithInterval(null, interval);
    }

    public static String getMinuteWithInterval(String pattern, int interval) {
        String p = DEFAULT_PATTERN;
        if (StringUtils.isNotBlank(pattern)) {
            p = pattern;
        }
        return LocalDateTime.now().plusMinutes(interval).format(DateTimeFormatter.ofPattern(p));
    }

    public static String getStartTimeOfDay() {
        LocalDate localDate = LocalDate.now();
        return localDate.format(DateTimeFormatter.ofPattern(PATTERN_PADDING_ZERO));
    }

    public static Date getStartDateOfDay() {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    public static Date getStartDateOfDay(LocalDateTime time) {
        LocalDateTime localDateTime = time;
        LocalDate localDate = localDateTime.toLocalDate();
        LocalTime localTime = LocalTime.of(0, 0, 0);
        localDateTime = LocalDateTime.of(localDate, localTime);
        Date ds = DateUtil.transform(localDateTime);
        return ds;
    }

    public static Date getStartDateOfDay(String time) {
        LocalDateTime localDateTime = DateUtil.formatToLocalDateTime(time);
        LocalDate localDate = localDateTime.toLocalDate();
        LocalTime localTime = LocalTime.of(0, 0, 0);
        localDateTime = LocalDateTime.of(localDate, localTime);
        Date ds = DateUtil.transform(localDateTime);
        return ds;
    }

    public static String getStartTimeOfDay(String time) {
        return format(time, PATTERN_PADDING_ZERO);
    }

    public static String format(String date, String pattern) {
        try {
            SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_PATTERN);
            Date d = formatter.parse(date);
            return new SimpleDateFormat(pattern).format(d);
        } catch (Exception e) {
            LOGGER.info("method [format] has error, ", e);
        }
        return date;
    }

    public static String format(String date) {
        return format(date, SHOW_PATTERN);
    }

    public static boolean validateFormat(String date, String pattern) {
        boolean flag = true;
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        try {
            formatter.setLenient(false);
            formatter.parse(date);
        } catch (ParseException e) {
            flag = false;
        }
        return flag;
    }

    public static boolean validateFormat(String date) {
        return validateFormat(date, DEFAULT_PATTERN);
    }

    /**
     * æ ¹æ®è¾å¥æ¶é´ï¼è·åé´éä¹åçæ¶é´
     *
     * @param date     yyyyMMddHHmm
     * @param interval åé
     * @return
     */
    public static String minusAndGet(String date, long interval) {
        return minusAndGet(date, interval, DEFAULT_PATTERN);
    }

    public static String minusAndGet(String date, long interval, String pattern) {
        String p = DEFAULT_PATTERN;
        if (StringUtils.isNotBlank(pattern)) {
            p = pattern;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(p);
        if (StringUtils.isBlank(date)) {
            return LocalDateTime.now().format(formatter);
        }
        return LocalDateTime.parse(date, formatter).minusMinutes(interval).format(formatter);
    }

    /**
     * æ ¹æ®è¾å¥æ¶é´ï¼è·åé´éä¹åçæ¶é´
     *
     * @param date     yyyyMMddHHmm
     * @param interval åé
     * @return
     */
    public static String incrAndGet(String date, long interval) {
        return incrAndGet(date, interval, DEFAULT_PATTERN);
    }

    /**
     * å¢å æå®å¤©æ°
     *
     * @param date
     * @param plusDay
     * @return
     */
    public static Date incrDayAndGet(Date date, Integer plusDay) {
        if (Objects.isNull(date) || Objects.isNull(plusDay)) {
            return null;
        } else {
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(date);
            calendar.add(Calendar.DATE, plusDay);
            return calendar.getTime();
        }
    }

    /**
     * å¢å æå®åéæ°
     *
     * @param date
     * @param min
     * @return
     */
    public static Date incrMinAndGet(Date date, Integer min) {
        if (Objects.isNull(date) || Objects.isNull(min)) {
            return null;
        } else {
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(date);
            calendar.add(Calendar.MINUTE, min);
            return calendar.getTime();
        }
    }

    public static String incrAndGet(String date, long interval, String pattern) {
        String p = DEFAULT_PATTERN;
        if (StringUtils.isNotBlank(pattern)) {
            p = pattern;
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(p);
        if (StringUtils.isBlank(date)) {
            return LocalDateTime.now().format(formatter);
        }
        return LocalDateTime.parse(date, formatter).plusMinutes(interval).format(formatter);
    }

    /**
     * è¾å¥æ¶é´ï¼è½¬æ¢ä¸ºLocalDateTime
     *
     * @param date yyyyMMddHHmm
     * @return
     */
    public static LocalDateTime formatToLocalDateTime(String date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DEFAULT_PATTERN);
        if (StringUtils.isBlank(date)) {
            return LocalDateTime.now();
        }
        return LocalDateTime.parse(date, formatter);
    }

    /**
     * è¾å¥æ¶é´ï¼è½¬æ¢ä¸ºLocalDateTime
     *
     * @param date    æ¥æ
     * @param parrern æ¥ææ ¼å¼
     * @return
     */
    public static LocalDateTime formatToLocalDateTime(String date, String parrern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(parrern);
        if (StringUtils.isBlank(date)) {
            return LocalDateTime.now();
        }
        return LocalDateTime.parse(date, formatter);
    }

    /**
     * æ ¹æ®è¾å¥æ¶é´ï¼è¾å¥æ¶é´æ ¼å¼
     * è¾åºæå®æ ¼å¼
     *
     * @param dateTime æ¶é´
     * @param pattern  æ ¼å¼
     * @return
     */
    public static String format(LocalDateTime dateTime, String pattern) {
        return dateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    public static LocalDateTime transform(Date date) {
        if (null == date) {
            return null;
        }
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        return instant.atZone(zoneId).toLocalDateTime();
    }

    public static Date transform(LocalDateTime localDateTime) {
        if (null == localDateTime) {
            return null;
        }
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        return Date.from(zonedDateTime.toInstant());
    }

    public static Date transform(Long times) {
        if (null == times) {
            return null;
        }
        Instant instant = Instant.ofEpochMilli(Long.valueOf(times));
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return transform(localDateTime);
    }

    /**
     * è¾å¥æ¶é´ï¼è¾åºä¾¿äºéè¯»çæ ¼å¼ {@PATTERN_PADDING_ZERO}
     *
     * @param date
     * @return
     */
    public static String format(LocalDateTime date) {
        return format(date, SHOW_PATTERN);
    }

    /**
     * æ ¹æ®è¾å¥çæ¶é´åæ¶é´é´éï¼è·åintervalå¤©ä¹åçæ¶é´
     *
     * @param date     yyyyMMddHHmm
     * @param interval åé
     * @return
     */
    public static String getTimeWithMinusDays(String date, long interval) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DEFAULT_PATTERN);
        if (StringUtils.isBlank(date)) {
            return LocalDateTime.now().format(formatter);
        }
        return LocalDateTime.parse(date, formatter).minusDays(interval).format(formatter);
    }

    /**
     * æ ¹æ®è¾å¥çæ¶é´åæ¶é´é´éï¼è·åintervalå¤©ä¹åçæ¶é´
     *
     * @param date     yyyyMMddHHmm
     * @param interval åé
     * @return
     */
    public static String getTimeWithPlusDays(String date, long interval) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DEFAULT_PATTERN);
        if (StringUtils.isBlank(date)) {
            return LocalDateTime.now().format(formatter);
        }
        return LocalDateTime.parse(date, formatter).plusDays(interval).format(formatter);
    }

    public static Date getDateWithPattern(Date date, String pattern) {
        if (date == null) {
            date = new Date();
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        String dateString = sdf.format(date);
        return sdf.parse(dateString, new ParsePosition(8));
    }

    public static Date formateDateString(String date, String pattern) {
        if (StringUtils.isBlank(date) || StringUtils.isBlank(pattern)) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            return sdf.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * è·åç°å¨æ¶é´
     *
     * @returnè¿åç­æ¶é´æ ¼å¼ yyyy-MM-dd
     */
    public static Date getNowDateShort(Date date, String pattern) {
        if (StringUtils.isEmpty(pattern)) {
            pattern = SHOW_PATTERN_DATE;
        }
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        String dateString = formatter.format(date);
        ParsePosition pos = new ParsePosition(0);
        Date currentTime_2 = formatter.parse(dateString, pos);
        return currentTime_2;
    }

    /**
     * å°dateæç§ç»å®formatè½¬ä¸ºå­ç¬¦ä¸²
     *
     * @param date
     * @param format
     * @return
     */
    public static String format(Date date, String format) {
        if (StringUtils.isEmpty(format)) {
            format = DEFAULT_PATTERN;
        }
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        return formatter.format(date);
    }

    public static Date parse(String date, String format) {
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        try {
            return formatter.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * æ ¹æ®ä¼ å¥çåéè·åæ¶é´ min>0 å½åæ¶é´ä¹å min
     *
     * @param min
     * @return
     */
    public static String getBeforeTimeByMin(Integer min) {
        SimpleDateFormat sdf = new SimpleDateFormat(DEFAULT_PATTERN);
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.add(Calendar.MINUTE, min);
        String time = sdf.format(beforeTime.getTime());
        return time;
    }

    /**
     * æ ¹æ®ä¼ å¥çåéè·åæ¶é´ min>0 å½åæ¶é´ä¹å min
     *
     * @param min
     * @return
     */
    public static Date getDateBeforeTimeByMin(Integer min) {
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.add(Calendar.MINUTE, min);
        return beforeTime.getTime();
    }

    /**
     * æ ¹æ®ä¼ å¥çå°æ¶è·åæ¶é´ hour>0 å½åæ¶é´ä¹å hour<0 å½åæ¶é´ä¹å
     *
     * @param hour
     * @return
     */
    public static Date getDateBeforeTimeByHour(Integer hour) {
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.add(Calendar.HOUR, hour);
        return beforeTime.getTime();
    }

    /**
     * æ ¹æ®ä¼ å¥çåéè·åæ¶é´ day>0 å½åæ¶é´ä¹å day<0 å½åæ¶é´ä¹å
     *
     * @param day
     * @return
     */
    public static Date getDateBeforeTimeByDay(Integer day) {
        Calendar beforeTime = Calendar.getInstance();
        beforeTime.add(Calendar.DAY_OF_MONTH, day);
        return beforeTime.getTime();
    }

    public static long getMinuteByDate(Date start, Date end) {
        long between = start.getTime() - end.getTime();
        long day = between / (24 * 60 * 60 * 1000);
        long hour = (between / (60 * 60 * 1000) - day * 24);
        long min = ((between / (60 * 1000)) - day * 24 * 60 - hour * 60);
//long s = (between / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);
        return day * 24 * 60 + hour * 60 + min;
    }

    /**
     * ææ¶é´çç§åæ¯«ç§ç½®é¶
     *
     * @param date
     * @return
     */
    public static Date getDateTimeWithZeroSecond(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * åå»æå®åéæ°
     *
     * @param date
     * @param interval
     * @return
     */
    public static Date minusMinute(Date date, int interval) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) - interval);
        return calendar.getTime();
    }

    /**
     * æ ¹æ®ä¼ å¥çæ¶é´åæ°å­ï¼è¿åå½ååéæ¯å¦å¯ä»¥è¢«æ´é¤
     *
     * @param date
     * @param num
     * @return
     */
    public static boolean getMumByDateMinute(Date date, int num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int minute = calendar.get(Calendar.MINUTE);
        if (minute == 0) {
            minute = 60;
        }
        if (num > 0 && minute % num == 0) {
            return true;
        }
        return false;
    }
}